
    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>ConcurrentHashMapJava并发集合的典范 - 学习卡片</title>
      <style>
        body { font-family: sans-serif; background-color: #f0f8ff; color: #333; display: flex; flex-direction: column; align-items: center; padding: 50px 20px; }
        .header h1 { font-size: 32px; }
        .grid-container { display: grid; grid-template-columns: repeat(3, 1fr); gap: 28px; width: 100%; max-width: 1200px; }
        .card-container { perspective: 1200px; cursor: pointer; height: 250px; }
        .card { width: 100%; height: 100%; position: relative; transform-style: preserve-3d; transition: transform 0.7s; border-radius: 16px; box-shadow: 0 4px 16px rgba(0,0,0,0.08); }
        .card-container.flipped .card { transform: rotateY(180deg); }
        .card-face { position: absolute; width: 100%; height: 100%; backface-visibility: hidden; display: flex; flex-direction: column; box-sizing: border-box; border-radius: 16px; background-color: #fff; padding: 24px; }
        .card-back { background-color: #f0fff4; transform: rotateY(180deg); justify-content: space-between; }
        .card-category { font-size: 14px; color: #0052d9; margin-bottom: 8px; font-weight: 500; }
        .card-question { font-size: 20px; font-weight: 500; flex-grow: 1; display: flex; align-items: center; justify-content: center; text-align: center; }
        .card-answer-wrapper { flex-grow: 1; overflow-y: auto; }
        .card-answer { font-size: 15px; line-height: 1.7; }
        .card-footer { font-size: 13px; color: #8a919f; border-top: 1px solid #f0f0f0; padding-top: 16px; margin-top: 16px; }
        .card-source { font-size: 13px; color: #8a919f; border-top: 1px solid #f0f0f0; padding-top: 12px; margin-top: 12px; }
      </style>
    </head>
    <body>
      <div class="header">
        <h1>ConcurrentHashMapJava并发集合的典范 - 学习卡片</h1>
      </div>
      <div class="grid-container">
        
    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">技术</div>
          <div class="card-question">文档中描述的Java并发Map实现经历了哪三个主要的演进阶段？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">技术</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">第一代是使用`Collections.synchronizedMap`实现的“全表锁”；第二代是JDK 7及以前的ConcurrentHashMap，采用“分段锁”设计；第三代是JDK 8及以后的ConcurrentHashMap，采用“CAS+Synchronized”机制。</div>
          </div>
          <div class="card-source">来源: 1.1 从“全表锁”到“分段锁”再到“CAS+Synchronized”</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">机制</div>
          <div class="card-question">JDK 7中ConcurrentHashMap的“分段锁”机制是如何工作的？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">机制</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">JDK 7的ConcurrentHashMap将整个Map数据结构划分为多个段（Segment），默认为16个。每个Segment都拥有自己独立的锁（ReentrantLock），并且内部结构类似一个小的HashMap。当操作需要加锁时，只需锁定对应数据所在的Segment，不同Segment之间的操作可以并发执行，从而提高了并发性能。</div>
          </div>
          <div class="card-source">来源: 1.2 JDK 7中的分段锁设计</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">机制</div>
          <div class="card-question">相比于JDK 7的分段锁，JDK 8的ConcurrentHashMap在并发控制上做了哪些核心改变？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">机制</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">JDK 8摒弃了分段锁，转而采用粒度更细的“CAS+Synchronized”方案。它直接对数组中的每个桶（bucket）进行锁定。在插入数据时，如果目标桶为空，会使用无锁的CAS操作尝试插入；如果发生哈希冲突，则使用synchronized关键字锁定该桶的头结点，仅对该桶内的操作加锁，极大地降低了锁的范围。</div>
          </div>
          <div class="card-source">来源: 1.3 JDK 8中的CAS+Synchronized方案</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">特性</div>
          <div class="card-question">为什么JDK 8中ConcurrentHashMap的get（读取）操作能够实现完全无锁？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">特性</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">get操作的无锁实现依赖于`volatile`关键字。核心数据结构如Node节点的`val`（值）和`next`（下一个节点指针）以及存储节点的`table`数组都被声明为`volatile`。这保证了写操作对内存的修改对读线程立即可见，从而可以在不加锁的情况下安全地读取数据。</div>
          </div>
          <div class="card-source">来源: 3.2 get操作的无锁设计</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">机制</div>
          <div class="card-question">在JDK 8的ConcurrentHashMap中，当一个桶的链表过长时会发生什么？触发条件是什么？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">机制</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">当一个桶中的链表长度超过阈值（默认为8）时，该链表会转换为红黑树，以将查找时间复杂度从O(n)优化到O(log n)。这个转换有两个触发条件：1. 链表长度超过8；2. Map的整体容量必须大于等于64，否则会优先选择扩容而不是树化。</div>
          </div>
          <div class="card-source">来源: 4.4 红黑树优化大哈希桶性能</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">机制</div>
          <div class="card-question">JDK 8的ConcurrentHashMap是如何实现多线程协作扩容的？ForwardingNode在其中扮演什么角色？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">机制</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">扩容操作被分解成多个任务，允许多个线程参与。每个线程负责迁移一部分桶的数据。当一个桶被成功迁移后，会在原table的对应位置放置一个`ForwardingNode`。这个特殊节点起标记作用，告知其他线程该桶已处理完毕，并指向新的table，帮助后续操作定位到新表或加入协作扩容。</div>
          </div>
          <div class="card-source">来源: 3.3 resize操作的协作机制</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">技术</div>
          <div class="card-question">在计算元素总数（size）时，JDK 8的ConcurrentHashMap如何避免高并发下的锁竞争？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">技术</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">它采用了一种类似于`LongAdder`的设计。维护一个基础计数值`baseCount`和一个`CounterCell`数组。在并发更新时，线程首先尝试用CAS更新`baseCount`。如果存在竞争导致失败，线程会被分配到`CounterCell`数组中的一个单元格进行增减操作，分散了计数压力。最终的size是`baseCount`与所有`CounterCell`中值的总和。</div>
          </div>
          <div class="card-source">来源: 3.4 size计算的一致性保证</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">理论</div>
          <div class="card-question">文档总结了ConcurrentHashMap设计中为了优化锁粒度而采用的四种核心思路是什么？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">理论</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">1. 空间换时间：使用额外的数组结构来减少锁竞争。2. 降低锁粒度：从全表锁演进到分段锁，再到更细的桶锁。3. 避免不必要的锁：例如读操作完全无锁设计。4. 乐观并发策略：优先尝试CAS无锁操作，失败后才回退到加锁。</div>
          </div>
          <div class="card-source">来源: 1.4 锁粒度优化思路</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">机制</div>
          <div class="card-question">在JDK 8的`put`操作中，锁定机制的具体流程是怎样的？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">机制</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">`put`操作首先计算哈希并定位到桶。如果目标桶为空，它会使用CAS操作无锁地插入新节点。如果目标桶不为空，说明发生冲突，此时它会使用`synchronized`关键字锁定该桶的头结点，然后在同步块内部遍历链表或红黑树，执行更新或插入操作。这种策略保证了只在必要时才加锁，且锁的范围极小。</div>
          </div>
          <div class="card-source">来源: 2.3 头结点锁定机制</div>
        </div>
      </div>
    </div>

      </div>
    </body>
    </html>
